test: expand unit test coverage for gitrun/repocache/vendordir/projlock#45
Conversation
Codecov Report❌ Patch coverage is
📢 Thoughts on this report? Let us know! |
PR Summary by QodoTests: expand unit coverage for gitrun/repocache/vendordir/projlock
AI Description
Diagram
High-Level Assessment
Files changed (9)
|
Code Review by Qodo
Context used✅ Compliance rules (platform):
15 rules 1. repocache_internal_test.go uses repocache
|
| @@ -0,0 +1,168 @@ | |||
| // Copyright 2026 The Graft Authors | |||
|
|
|||
| package repocache | |||
There was a problem hiding this comment.
1. repocache_internal_test.go uses repocache 📘 Rule violation ▣ Testability
Newly added Go test files under non-main packages are declaring the internal package names (repocache and vendordir) instead of using external _test-suffixed packages (repocache_test and vendordir_test). This violates Rule 996222’s requirement that new *_test.go files for non-main packages use an external test package name with a _test suffix.
Agent Prompt
## Issue description
Two newly added `*_test.go` files are using internal package declarations (`package repocache` and `package vendordir`) instead of external test packages (`repocache_test` / `vendordir_test`), which violates the external test package requirement (Rule 996222) for non-main packages.
## Issue Context
- `internal/repocache/repocache_internal_test.go` currently tests unexported helpers (e.g., `ensureBare`, `fetchRef`, `fetchAllRefs`), which is why it was written as an internal-package test.
- `internal/vendordir/linkmatch_internal_test.go` currently calls the unexported helper `cleanLinkTarget`, which is only accessible from the `vendordir` package.
## Fix Focus Areas
- internal/repocache/repocache_internal_test.go[1-10]
- internal/vendordir/linkmatch_internal_test.go[1-6]
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| canary := filepath.Join(t.TempDir(), "canary") | ||
|
|
||
| if err := fetchRef(t.Context(), bare, "--upload-pack=touch "+canary, false); err == nil { | ||
| t.Fatal("fetchRef succeeded on an option-like ref, want an error") | ||
| } | ||
|
|
||
| if _, err := os.Stat(canary); err == nil { | ||
| t.Fatal("ref was parsed as a git option instead of a literal ref") | ||
| } |
There was a problem hiding this comment.
2. Misleading injection test 🐞 Bug ≡ Correctness
TestFetchRef_rejectsOptionLikeRef relies on a non-portable "touch" canary and passes "--upload-pack=touch <path>" as a single argv element, so the canary check does not reliably validate the intended option-injection property and may pass/fail for the wrong reason. This weakens confidence that future regressions in argument separation will be caught.
Agent Prompt
### Issue description
`TestFetchRef_rejectsOptionLikeRef` aims to verify option-injection protection, but it depends on an external `touch` binary and constructs the payload as a single argv string containing a space. Because the code under test forwards args directly to `exec.CommandContext` (no shell splitting), this test does not robustly prove the security property it claims.
### Issue Context
The actual property to validate is: `fetchRef` must insert `--` so that any ref beginning with `-` is treated as a positional refspec, not as a git flag.
### Fix Focus Areas
- internal/repocache/repocache_internal_test.go[15-41]
- internal/gitrun/gitrun.go[72-105]
### Suggested fix approach
- Replace the `touch` canary strategy with a platform-independent assertion.
- Option A (recommended): stub `git` via a temporary script/executable placed first in `PATH`.
- The stub should record received argv to a temp file and exit non-zero.
- Call `fetchRef(...)` and assert the recorded argv contains `fetch ... -- origin <ref>` (i.e., `--` appears before `origin`, and the ref is present as a separate argv element even when it starts with `--`).
- Implement the stub in a cross-platform way (e.g., create a `.sh` with shebang on unix + a `.cmd` on Windows).
- Option B: assert on git’s stderr shape in a way that does not depend on external binaries (less robust due to message variability).
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
| go func() { | ||
| time.Sleep(1200 * time.Millisecond) | ||
| release1() | ||
| }() |
There was a problem hiding this comment.
3. Slow time-based test 🐞 Bug ➹ Performance
TestAcquire_printsWaitHintAfterOneSecond uses a fixed 1.2s sleep to trigger the >1s wait-hint, which unconditionally slows the test suite and is more sensitive to timing/scheduler variability than necessary. The same behavior can be tested deterministically by making the wait threshold configurable in tests.
Agent Prompt
### Issue description
The unit test `TestAcquire_printsWaitHintAfterOneSecond` introduces a hard-coded `time.Sleep(1200 * time.Millisecond)` to force the >1s warning path. This adds ~1.2s wall-clock time to every test run and can be made faster and more deterministic.
### Issue Context
`projlock.Acquire` uses constants (`warnAfter = time.Second`, `pollInterval = 50ms`) to decide when to print the wait hint.
### Fix Focus Areas
- internal/projlock/projlock.go[23-76]
- internal/projlock/projlock_test.go[114-143]
### Suggested fix approach
- Make timing parameters test-configurable while keeping production defaults.
- e.g., change `warnAfter` / `pollInterval` from `const` to `var` (package-private), or introduce an unexported helper `acquireWithTimings(ctx, root, warn, warnAfter, pollInterval)` used by `Acquire`.
- In the test, set `warnAfter` to a small duration (e.g., 10ms) and `pollInterval` to 1ms, then release the lock after e.g. 20–30ms.
- Optionally add a small synchronization step (channel) to ensure the contending goroutine has started waiting before releasing, so the hint path is guaranteed to be exercised.
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools
cb2d22d to
b17f985
Compare
…jlock
gitrun and repocache had bare-fetch option-injection guards ("--" before
repo/ref operands) with no regression test for the fix, and several packages
had large untested surfaces: gitrun's own git-exec helpers (19% coverage),
repocache's fallback-fetch fallthrough (isTag/pseudoVersion/fetchAll at 0%),
vendordir's link-mode validation (LinkMatches/cleanLinkTarget at 0%), and
projlock's lock-contention path (blocking wait, wait-hint, ctx cancellation).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
b17f985 to
ed6da56
Compare
filepath.Clean rewrites "/" to the host OS separator, so the forward-slash expectations failed on windows-latest CI. Run them through filepath.FromSlash to match Clean's actual per-platform output.
Line 93's remote-add error wrap can only fail if git rejects the call right after a fresh git init --bare succeeds, with no seam to force that between the two -- the same idiom recurs throughout the codebase, so a hard 80% target keeps tripping on single unreachable branches rather than real gaps.
832e569 to
21ff3bc
Compare
Summary
internal/gitrun(Run/RunEnv, RemoteURL, NetworkErr, Reachable, FetchSHA, FetchAll, CommitTime, RemoveAll) — package coverage was 19.3%, driven almost entirely by other packages' integration tests.internal/repocachetests forisTag/pseudoVersion(pure helpers, 0% covered),fetchAll/fetchAllRefs(spec §5.5 step-3 fallback),commitGoneErr, and an all-refs-fallbackEnsureCommitscenario.internal/vendordirtests forLinkMatches/cleanLinkTarget(link-mode validation, 0% covered).internal/projlocktests for the lock-contention path: blocking until ctx cancellation, and the >1s wait-hint message.codecov.yml(80% patch coverage gate) andinternal/repocache/repocache_internal_test.gothat were already staged locally as part of the option-injection hardening ingitrun.go/repocache.go(the"--"separator before repo/ref/version operands passed to git).Test plan
go build ./...gofmt -lcleango test -race ./...— all packages pass